package com.bolt.core.view.freemarker;

import com.bolt.common.convert.Convert;
import com.bolt.common.utils.SpringContextUtil;
import com.bolt.common.utils.StrUtil;
import com.bolt.core.view.components.*;
import com.bolt.core.view.config.PageRepository;
import com.bolt.support.freemarker.DirectiveUtil;
import freemarker.core.Environment;
import freemarker.ext.beans.StringModel;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;

import java.io.IOException;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Created by Administrator on 2019/3/29.
 */
public class FormTemplateModel extends TagModel {

    private Form getTag(Map params) {
        Object var = params.get("tag");
        if (var == null) {
            return null;
        }
        Object model = ((StringModel) var).getWrappedObject();
        if (model.getClass().isAssignableFrom(Form.class)) {
            return (Form) model;
        }
        return null;
    }


    private String getToggle(Map params) {
        return DirectiveUtil.getString(params, "toggle");
    }

    private String getSubmitBtnText(Map params) {
        return DirectiveUtil.getString(params, "submitBtnText");
    }

    private String getCancelBtnText(Map params) {
        return DirectiveUtil.getString(params, "cancelBtnText");
    }

    private String getId(Map params) {
        return DirectiveUtil.getString(params, "id");
    }

    private String getPath(Map params) {
        return DirectiveUtil.getString(params, "path");
    }

    private String getSaveAction(Map params) {
        return DirectiveUtil.getString(params, "saveAction");
    }

    private String getUpdateAction(Map params) {
        return DirectiveUtil.getString(params, "updateAction");
    }


    public boolean isHaveSubmitBtn(Map params) {
        return DirectiveUtil.getBoolean(params, "haveSubmitBtn", true);
    }

    Object getEntity(Map params) {
        return getBenaParam(params, "entity");
    }

    boolean isUpdateState() {
        return Convert.toBool(getRequest().getAttribute(Form.FORM_UPDATESTATE), false);
    }

    void setUpdateState(boolean updateState) {
        getRequest().setAttribute(Form.FORM_UPDATESTATE, updateState);
    }


    @Override
    public ComponentsBase getUI(Map params) {
        Form form = getTag(params);
        if (null == form) {
            PageView page = getPageRepository().findPage(getPath(params));
            form = page.getForm(getId(params));
        }
        String saveAction = this.getSaveAction(params);
        if (StrUtil.isNotBlank(saveAction)) {
            form.setSaveAction(saveAction);
        }
        String updateAction = this.getUpdateAction(params);
        if (StrUtil.isNotBlank(updateAction)) {
            form.setUpdateAction(updateAction);
        }

        String submitBtnText = this.getSubmitBtnText(params);
        if (StrUtil.isNotBlank(submitBtnText)) {
            form.addParameter("submitBtnText", submitBtnText);
        }

        String cancelBtnText = this.getUpdateAction(params);
        if (StrUtil.isNotBlank(cancelBtnText)) {
            form.addParameter("cancelBtnText", cancelBtnText);
        }

        String toggle = this.getToggle(params);
        if (StrUtil.isNotBlank(toggle)) {
            form.addParameter("toggle", toggle);
        }

        form.setHaveSubmitBtn(isHaveSubmitBtn(params));


        return form;
    }

    @Override
    protected void populateParams(ComponentsBase component, Map<String, TemplateModel> params) {
        super.populateParams(component, params);
        Form form = (Form) component;
        List<List<FormItem>> group = form.getGroup();
        group.forEach(k -> {
            k.forEach(i -> {
                i.setTemplateDir(form.getTemplateDir());
                i.setTheme(form.getTheme());
                i.setTemplateEngine(form.getTemplateEngine());
            });
        });
        List<FormItem> hiddenItems = form.getHiddenFormItems();
        hiddenItems.forEach(k -> {
            k.setTemplateDir(form.getTemplateDir());
            k.setTheme(form.getTheme());
            k.setTemplateEngine(form.getTemplateEngine());
        });
    }

    public void evaluateExpressions(Map params, ComponentsBase component) {
        Form form = (Form) component;
        Object entityBean = getEntity(params);
        if (!Objects.isNull(entityBean)) {
            getRequest().setAttribute(Form.PAGECONTEXT_FORMVALUES, entityBean);
        }
        if (getRequest().getAttribute(Form.PAGECONTEXT_FORMVALUES) != null) {
            setUpdateState(true);
        } else {
            setUpdateState(false);
            getRequest().setAttribute(Form.FORM_UPDATESTATE, false);
        }
        if (StrUtil.isBlank(form.getUpdateAction()) && StrUtil.isBlank(form.getSaveAction())) {
            getRequest().setAttribute(Form.FORM_ACTION_URL, form.getQueryAction());
        } else {
            getRequest().setAttribute(Form.FORM_ACTION_URL, isUpdateState() ? form.getUpdateAction() : form.getSaveAction());
        }

    }

    public void addValidator(FormItem item, Form form) {
        if ("combination".equals(item.getType())) {
            CombinationFormItem combination = (CombinationFormItem) item;
            for (FormItem formItem : combination.getCombinations()) {
                addValidator(formItem, form);
            }
        } else {
            ValidatorRule v = form.findValidator(item.getId());
            if (v != null) {
                item.addParameter("validator", v);
            }
        }
    }

    @Override
    public void render(ComponentsBase component, Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
        evaluateExpressions(params, component);
        Form form = (Form) component;
        component.start(getRequest(), getResponse(), env.getOut());
        List<List<FormItem>> group = form.getGroup();
        for (List<FormItem> row : group) {
            printFormItem(row, form, env.getOut());
        }
        for (FormItem item : form.getHiddenFormItems()) {
            item.start(getRequest(), getResponse(), env.getOut());
            item.end(getRequest(), getResponse(), env.getOut());
        }

        component.end(getRequest(), getResponse(), env.getOut());
    }

    private void printFormItem(List<FormItem> items, Form form, Writer writer) {
        try {
            if (items.size() == 1 && items.get(0) instanceof FieldSet) {
                FieldSet fieldset = ((FieldSet) items.get(0));
                fieldset.start(getRequest(), getResponse(), writer);
                List<List<FormItem>> group = fieldset.getGroup();
                for (List<FormItem> row : group) {
                    printFormItem(row, form, writer);
                }
                fieldset.end(getRequest(), getResponse(), writer);
            } else {
                Decorate row = Decorate.buildRowDecorate();
                row.start(getRequest(), getResponse(), writer);
                for (FormItem item : items) {
                    if (item.isUpdateHidde() && isUpdateState()) {
                        continue;
                    }
                    addValidator(item, form);
                    Decorate column = Decorate.buildFormColumnDecorate(item);
                    column.start(getRequest(), getResponse(), writer);
                    column.end(getRequest(), getResponse(), writer);
                }
                row.end(getRequest(), getResponse(), writer);
            }

        } catch (Exception ex) {

        }
    }

    protected PageRepository getPageRepository() {
        PageRepository pageRepository = SpringContextUtil.getBean(PageRepository.class);
        return pageRepository;
    }
}

 